#!/usr/bin/python

# dnsdic.py
# script written by t0ka7a
# http://infond.blogspot.com
# licence new BSD
# 02/14/2010 v0.1
# performs a dictionnary search of available subdomains for a given domain name.
# for example, given owasp.net, the script will find mail.owasp.net, forums.owasp.net etc.

from socket import gethostbyname_ex
import threading
import sys
import time

NB_OF_THREADS_MAX = 330

################################################################
# print error message
def use (msg):
  sys.stderr.write ("%s\n\n" % msg)
  sys.stderr.write("exemple: %s -f ./dico.txt infond.blogspot.com\n\n" % sys.argv[0] )
  sys.exit (1)

################################################################
# print intro message
def intro ():
  sys.stdout.write ("\n")
  sys.stdout.write ("***************************************************\n")
  sys.stdout.write ("* program created by t0ka7a                       *\n")
  sys.stdout.write ("* http://infond.blogspot.com                      *\n")
  sys.stdout.write ("* under GNU 3.0 licence                           *\n")
  sys.stdout.write ("* v0.1 02/14/2010                                 *\n")
  sys.stdout.write ("* dns dictionnary search of hostnames in a subnet *\n")
  sys.stdout.write ("***************************************************\n\n")
  sys.stdout.write ("begin search...\n\n")


################################################################
# print hostnames associated with a list of IP
# each_hostname_tested = hostname we're working on. Ex: 'infond.blogspot.com'
def show_name(each_hostname_tested):
  global nb_of_names_found
  global lock
  #sys.stdout.write ("test: %s\n" % each_hostname_tested)
  try:
    sys.stdout.write( "%s %s %s\n" % ( gethostbyname_ex(each_hostname_tested)) )
    lock.acquire()
    nb_of_names_found += 1
    lock.release()
  except:
    ""    
  # release semaphore. Main() can then create a new thread
  semaphore.release()


################################################################
# main function
def main ():
  # begin = date of start
  begin = time.time()
  # lock = lock used by threads
  global lock
  lock = threading.Lock()
  # nb_of_names_found = nb of valid names we find
  global nb_of_names_found
  nb_of_names_found = 0
  # start NB_OF_THREADS_MAX threads
  global semaphore
  semaphore = threading.Semaphore(NB_OF_THREADS_MAX)

  intro()

  # test command line
  if len (sys.argv) != 4:
    use("wrong number of arguments")
  if sys.argv[1] != '-f':
    use("syntax error: (-f)")
  try:
    #hostname = hostname we work on. For example, 'infond.blogspot.com'
    hostname = sys.argv[3]
  except:
    use("wrong hostname")
  try:
    # filehandle = handle to the dictionnary file given in command line
    filehandle = open(sys.argv[2],'r')
  except:
    use("file %s can't be opened" % sys.argv[1])
  try:
    # dictionnary = list of names o the dictionnary file. Ex: (mail,ns,ns1)
    dictionnary = filehandle.readlines()
  except:
    use("can't create list of names from the dictionnary file. file should be written like this:\nmail\nns1\nns2\netc.")   
 
  for subname in dictionnary:
    # start NB_OF_THREADS_MAX threads
    # stop main thread if more than NB_OF_THREADS_MAX threads are running.
    semaphore.acquire()
    name_to_test = subname.rstrip('\n') + '.' + hostname
    current_thread = threading.Thread(None,show_name,None,(name_to_test,),None)
    try:
        current_thread.start()
    except:
      use("can't start so many threads.")

  # wait for the end of all threads
  while threading.activeCount() != 1:
    time.sleep(2)

  sys.stdout.write("\nend of search\n")
  sys.stdout.write("%i names tested, %i hostnames found, in %f s\n\n" % ( len(dictionnary), nb_of_names_found, time.time()-begin ))

main()

